package geppetto.cat.programs;


import geppetto.cat.alignments.AlignmentsSet;
import geppetto.cat.corpus.BilingualCorpus;
import geppetto.cat.models.AbstractModel;
import geppetto.phraseHMM.BijectiveHMM;
import geppetto.phraseHMM.IBMM1;
import geppetto.phraseHMM.RegularHMM;
import geppetto.phraseHMM.SymmetricHMM;

import java.io.IOException;






public class GenericMethods {

	
	public static BilingualCorpus[] initializeCorpus(String corpusDesc, int size, int maxSentenceLen)
	throws IOException {
		System.out.println("Loading Corpus");
		BilingualCorpus forwardCorpus = BilingualCorpus.getCorpusFromFileDescription(
		corpusDesc, size, maxSentenceLen);
		BilingualCorpus backwardCorpus = forwardCorpus.reverse();
		System.out.println("Finished Loading Corpus");
		BilingualCorpus[] results =  {forwardCorpus,backwardCorpus}; 
		return results;
}


	
	public static AbstractModel[] initializeModels(BilingualCorpus forwardCorpus, BilingualCorpus backwardCorpus,
			String modelName, String modelDir,double epsilon, double slack, int maxStep, int maxProjectionIterations) {
		
		System.out.println("Loading Model");
		AbstractModel[] models = new AbstractModel[2];
		if (modelName.equalsIgnoreCase("regularHMM")) {
			models[0] = RegularHMM.loadModel(forwardCorpus, modelDir + "/MHMM/forward");
			models[1] = RegularHMM.loadModel(backwardCorpus, modelDir + "/MHMM/backward");			
		}else if (modelName.equalsIgnoreCase("symmetric")) {
			models[0] = SymmetricHMM.loadModel(forwardCorpus, backwardCorpus, modelDir + "/MHMM/",epsilon,slack,maxStep,maxProjectionIterations);
			models[1] = ((SymmetricHMM) models[0]).getBackwardModel(); 
		}else if (modelName.equalsIgnoreCase("bijective")) {	
			models[0] = BijectiveHMM.loadModel(forwardCorpus, modelDir + "/MHMM/forward",epsilon,slack,maxStep,maxProjectionIterations);
			models[1] = BijectiveHMM.loadModel(backwardCorpus, modelDir + "/MHMM/backward",epsilon,slack,maxStep,maxProjectionIterations);
			System.out.println("slack " + ((BijectiveHMM) models[0])._slack);
			System.out.println("epsilon " + ((BijectiveHMM) models[0])._epsilon);
			System.out.println("max steps " + ((BijectiveHMM) models[0])._maxStepSize);
			System.out.println("max number iterartions " + ((BijectiveHMM) models[0])._maxNumberIterations);
		} else {
			System.out.println("Unknown Model");
			System.exit(1);
		}
		System.out.println("Finished Loading Model");
		return models;
	}
	
	
	public static AbstractModel[] initializeModelsFullDir(BilingualCorpus forwardCorpus, BilingualCorpus backwardCorpus,
			String modelName, String forwardModelDir, String backwardModelDir,double epsilon, double slack, int maxStep, int maxProjectionIterations) {
		
		System.out.println("Loading Model");
		AbstractModel[] models = new AbstractModel[2];
		if (modelName.equalsIgnoreCase("regularHMM")) {
			models[0] = RegularHMM.loadModel(forwardCorpus, forwardModelDir);
			models[1] = RegularHMM.loadModel(backwardCorpus, backwardModelDir);			
		}else if (modelName.equalsIgnoreCase("symmetric")) {
			models[0] = SymmetricHMM.loadModel(forwardCorpus, backwardCorpus, forwardModelDir ,epsilon,slack,maxStep,maxProjectionIterations);
			models[1] = ((SymmetricHMM) models[0]).getBackwardModel(); 
			System.out.println("slack " + ((SymmetricHMM) models[0]).slack);
			System.out.println("epsilon " + ((SymmetricHMM) models[0]).optimizationPrecision);
			System.out.println("max steps " + ((SymmetricHMM) models[0])._maxStepSize);
			System.out.println("max number iterartions " + ((SymmetricHMM) models[0])._maxNumberIterations);
		}else if (modelName.equalsIgnoreCase("bijective")) {	
			models[0] = BijectiveHMM.loadModel(forwardCorpus, forwardModelDir,epsilon,slack,maxStep,maxProjectionIterations);
			models[1] = BijectiveHMM.loadModel(backwardCorpus, backwardModelDir,epsilon,slack,maxStep,maxProjectionIterations);
			System.out.println("slack " + ((BijectiveHMM) models[0])._slack);
			System.out.println("epsilon " + ((BijectiveHMM) models[0])._epsilon);
			System.out.println("max steps " + ((BijectiveHMM) models[0])._maxStepSize);
			System.out.println("max number iterartions " + ((BijectiveHMM) models[0])._maxNumberIterations);
		} else if(modelName.equalsIgnoreCase("M1")){
			models[0] = IBMM1.loadModel(forwardCorpus, forwardModelDir);
			models[1] = IBMM1.loadModel(backwardCorpus, backwardModelDir);
		} else if(modelName.equalsIgnoreCase("BijectiveM1")){
			models[0] = IBMM1.loadModel(forwardCorpus, forwardModelDir);
			models[1] = IBMM1.loadModel(backwardCorpus, backwardModelDir);
		} else if(modelName.equalsIgnoreCase("SymmetricM1")){
			models[0] = IBMM1.loadModel(forwardCorpus, forwardModelDir);
			models[1] = IBMM1.loadModel(backwardCorpus, backwardModelDir);
		}
		else {
			System.out.println("Unknown Model");
			System.exit(1);
		}
		System.out.println("Finished Loading Model");
		return models;
	}
	
	
	public static AlignmentsSet[] getAlignmentSet(AbstractModel mf, AbstractModel mb, String decodingType, boolean projectTestTime, float posterior){
		AlignmentsSet[] results = new AlignmentsSet[2];
		if (decodingType.equalsIgnoreCase("viter")) {
			results[0] = mf.viterbiAlignments(BilingualCorpus.TEST_CORPUS,projectTestTime);
			results[1] = mb.viterbiAlignments(BilingualCorpus.TEST_CORPUS,projectTestTime);
		} else if (decodingType.equalsIgnoreCase("post-aer")) {
			float forwardThresh = mf
					.tuneTreshholdAER(BilingualCorpus.DEV_CORPUS,projectTestTime);
			float backwardThresh = mb
					.tuneTreshholdAER(BilingualCorpus.DEV_CORPUS,projectTestTime);
			results[0] = mf.posteriorAlignments(BilingualCorpus.TEST_CORPUS,
					forwardThresh,projectTestTime,true);
			results[1] = mb.posteriorAlignments(BilingualCorpus.TEST_CORPUS,
					backwardThresh, projectTestTime,true);
		} else if (decodingType.equalsIgnoreCase("post-f1")) {
			float forwardThresh = mf.tuneTreshholdF1(
					BilingualCorpus.DEV_CORPUS, posterior,projectTestTime);
			float backwardThresh = mb.tuneTreshholdF1(
					BilingualCorpus.DEV_CORPUS, posterior,projectTestTime);
			results[0] = mf.posteriorAlignments(BilingualCorpus.TEST_CORPUS,
					forwardThresh,projectTestTime,true);
			results[1] = mb.posteriorAlignments(BilingualCorpus.TEST_CORPUS,
					backwardThresh,projectTestTime,true);

		} else {
			System.out.println("Unknowon decoding");
			System.exit(1);
		}
		return results;
	}
	
	public static AlignmentsSet[] getAlignmentSet(BilingualCorpus forwardCorpus,BilingualCorpus backwardCorpus, 
			String modelDir, String modelName, boolean projectAtTestTime, String decodingType,
			double epsilon, double slack, int maxStep, int maxProjectionIterations,
			float posterior){
		AbstractModel[] models= GenericMethods.initializeModels(forwardCorpus, backwardCorpus, modelName, modelDir, 
				epsilon, slack, maxStep, maxProjectionIterations);
		return getAlignmentSet(models[0], models[1], decodingType, projectAtTestTime, posterior);
	}
	
}
